#include "derivadores.h"
#include "literal.h"
#include "expresion.h"
#include <stdlib.h>
#include <stdio.h>

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarVariable(const TAB* origen, TAB* destino) {
  TLiteral literal;
  TPila pila;
  int error;

  AB_Crear(destino,sizeof(TLiteral));
  P_Crear(&pila,sizeof(TLiteral));
  infijo_a_sufijo("1","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,RAIZ,&literal,&error);

  return 1;
}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarConstante(const TAB* origen, TAB* destino) {
  TLiteral literal;
  TPila pila;
  int error;

  AB_Crear(destino,sizeof(TLiteral));
  P_Crear(&pila,sizeof(TLiteral));
  infijo_a_sufijo("0","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,RAIZ,&literal,&error);

  return 1;
}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarSuma(const TAB* origen, TAB* destino) {
  TAB u,v,u1,v1;
  int error;
  TLiteral literal;

  AB_ElemCte(*origen,&literal);
  Expresion_Copiar_SubExpresion (origen,&u,IZQ);  //Genero termino U
  Expresion_Copiar_SubExpresion (origen,&v,DER);  //Genero termino V
  Expresion_Derivar(&u,&u1);
  Expresion_Derivar(&v,&v1);
  AB_Crear(destino,sizeof(TLiteral));
  AB_Insertar(destino,RAIZ,&literal,&error);
  AB_PegarSubarbol( &u1, destino, IZQ);
  AB_MoverCte(destino,RAIZ,&error);
  AB_PegarSubarbol( &v1, destino, DER);
  AB_MoverCte(destino,RAIZ,&error);

  AB_Vaciar(&u);
  AB_Vaciar(&v);
  AB_Vaciar(&u1);
  AB_Vaciar(&v1);
  return 1;
}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarResta(const TAB* origen, TAB* destino) {
  TAB u,v,u1,v1;
  int error;
  TLiteral literal;

  AB_ElemCte(*origen,&literal);
  Expresion_Copiar_SubExpresion (origen,&u,IZQ);  //Genero termino U
  Expresion_Copiar_SubExpresion (origen,&v,DER);  //Genero termino V
  Expresion_Derivar(&u,&u1);
  Expresion_Derivar(&v,&v1);
  AB_Crear(destino,sizeof(TLiteral));
  AB_Insertar(destino,RAIZ,&literal,&error);
  AB_PegarSubarbol( &u1, destino, IZQ);
  AB_MoverCte(destino,RAIZ,&error);
  AB_PegarSubarbol( &v1, destino, DER);
  AB_MoverCte(destino,RAIZ,&error);

  AB_Vaciar(&u);
  AB_Vaciar(&v);
  AB_Vaciar(&u1);
  AB_Vaciar(&v1);

  return 1;
}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarProducto(const TAB* origen, TAB* destino) {
  TExpresion u,u1,v,v1;
  TLiteral literal;
  TPila pila;
  int error;

  AB_Crear(destino,sizeof(TLiteral));
  if (!Expresion_Crear (&u)) return 0;
  if (!Expresion_Crear (&v)) return 0;

  Expresion_Copiar_SubExpresion (origen,&u,IZQ);  //Genero termino U
  Expresion_Copiar_SubExpresion (origen,&v,DER);  //Genero termino V
  Expresion_Derivar (&u, &u1);          //Genero termino U prima
  Expresion_Derivar (&v, &v1);          //Gemerp termino V prima


  P_Crear(&pila,sizeof(TLiteral));
  infijo_a_sufijo("+","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,RAIZ,&literal,&error);  //RAIZ= operador +

  infijo_a_sufijo("*","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,IZQ,&literal,&error); //HIJO IZQ = operador *
  AB_PegarSubarbol(&u1,destino,IZQ);
  AB_MoverCte(destino,RAIZ,&error);
  AB_MoverCte(destino,IZQ,&error);
  AB_PegarSubarbol(&v,destino,DER);

  AB_MoverCte(destino,RAIZ,&error);  //RAIZ = operador +
  AB_Insertar(destino,DER,&literal,&error); //HIJO DER = operador *
  AB_PegarSubarbol(&u,destino,IZQ);
  AB_MoverCte(destino,RAIZ,&error);
  AB_MoverCte(destino,DER,&error);
  AB_PegarSubarbol(&v1,destino,DER);
  AB_MoverCte(destino,RAIZ,&error);

  AB_Vaciar(&u);
  AB_Vaciar(&u1);
  AB_Vaciar(&v);
  AB_Vaciar(&v1);

  return 1;
}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarDivision(const TAB* origen, TAB* destino) {
  TExpresion u,u1,v,v1;
  TLiteral literal;
  TPila pila;
  int error;

  AB_Crear(destino,sizeof(TLiteral));
  if (!Expresion_Crear (&u)) return 0;
  if (!Expresion_Crear (&v)) return 0;

  Expresion_Copiar_SubExpresion (origen,&u,IZQ);  //Genero termino U
  Expresion_Copiar_SubExpresion (origen,&v,DER);  //Genero termino V
  Expresion_Derivar (&u, &u1);          //Genero termino U prima
  Expresion_Derivar (&v, &v1);          //Gemerp termino V prima

  P_Crear(&pila,sizeof(TLiteral));
  infijo_a_sufijo("/","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,RAIZ,&literal,&error);  //RAIZ= operador /

  infijo_a_sufijo("*","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,DER,&literal,&error); //HIJO DER = operador *
  AB_PegarSubarbol(&v,destino,DER);
  AB_MoverCte(destino,PAD,&error);
  AB_PegarSubarbol(&v,destino,IZQ);

  AB_MoverCte(destino,RAIZ,&error);   //RAIZ = operador /

  infijo_a_sufijo("-","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,IZQ,&literal,&error); //HIJO IZQ = operador -

  infijo_a_sufijo("*","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,IZQ,&literal,&error); //HIJO IZQ,HiJO IZQ = operador *
  AB_PegarSubarbol(&u1,destino,IZQ);
  AB_MoverCte(destino,PAD,&error);
  AB_PegarSubarbol(&v,destino,DER);

  AB_MoverCte(destino,RAIZ,&error);  //RAIZ = operador /
  AB_MoverCte(destino,IZQ,&error);  //HIJO IZQ = operador -

  AB_Insertar(destino,DER,&literal,&error); //HIJO DER,HIJO DER = operador *
  AB_PegarSubarbol(&u,destino,IZQ);
  AB_MoverCte(destino,PAD,&error);
  AB_PegarSubarbol(&v1,destino,DER);
  AB_MoverCte(destino,RAIZ,&error);

  AB_Vaciar(&u);
  AB_Vaciar(&u1);
  AB_Vaciar(&v);
  AB_Vaciar(&v1);

  return 1;
}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarPotencia(const TAB* origen, TAB* destino) {
  TExpresion u,u1;
  TLiteral literal;
  TPila pila;
  int error;
  char* s_potencia,*aux;

  AB_Crear(destino,sizeof(TLiteral));
  if (!Expresion_Crear (&u)) return 0;

  Expresion_Copiar_SubExpresion (origen,&u,IZQ);  //Genero termino U
  Expresion_Derivar (&u, &u1);          //Genero termino U prima
  AB_MoverCte(origen,RAIZ,&error);
  AB_MoverCte(origen,DER,&error);
  AB_ElemCte(*origen,&literal);
  Literal_AString(&literal,&s_potencia);
  Literal_Destruir(&literal);
  if (s_potencia[0]=='-'){
    aux=(char*)malloc(sizeof(char*)*(strlen(s_potencia)+3));
    strcpy(aux,"(");
    strcat(aux,s_potencia);
    strcat(aux,")");
    s_potencia=(char*)realloc(s_potencia,sizeof(char*)*(strlen(aux)+1));
    strcpy(s_potencia,aux);
    free(aux);
  }

  if(!strcmp(s_potencia,"0")){
    AB_MoverCte(origen,RAIZ,&error);
    AB_MoverCte(origen,IZQ,&error);
    AB_ElemCte(*origen,&literal);
    Literal_AString(&literal,&aux);
    Literal_Destruir(&literal);
    if(!strcmp(aux,"0")){
      free(aux);
      free(s_potencia);
      AB_Vaciar(&u);
      AB_Vaciar(&u1);
      return 0;
    }
    free(aux);
  }


  P_Crear(&pila,sizeof(TLiteral));

  infijo_a_sufijo("*","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,RAIZ,&literal,&error);  //RAIZ= operador *
  AB_PegarSubarbol(&u1,destino,IZQ);//HIJO IZQ = U prima

  AB_MoverCte(destino,RAIZ,&error);
  infijo_a_sufijo("*","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,DER,&literal,&error); //HIJO DER = operador *
  infijo_a_sufijo(s_potencia,"",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,IZQ,&literal,&error); //HIJO DER,HIJO IZQ = A

  AB_MoverCte(destino,PAD,&error);
  infijo_a_sufijo("^","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,DER,&literal,&error); //HIJO DER,HIJO DER = operador ^
  AB_PegarSubarbol(&u,destino,IZQ);

  AB_MoverCte(destino,PAD,&error);
  infijo_a_sufijo("-","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,DER,&literal,&error); //HIJO DER,HIJO DER,HIJO DER = -
  infijo_a_sufijo("1","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,DER,&literal,&error); //HIJO DER,HIJO DER,HIJO DER,HIJO DER = 1
  AB_MoverCte(destino,PAD,&error);
  infijo_a_sufijo(s_potencia,"",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,IZQ,&literal,&error); //HIJO DER,HIJO DER,HIJO DER,HIJO IZQ = A

  AB_MoverCte(destino,RAIZ,&error);

  free(s_potencia);
  AB_Vaciar(&u);
  AB_Vaciar(&u1);

  return 1;
}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarSeno(const TAB* origen, TAB* destino) {
TExpresion expr,deriv;
TLiteral literal;
TPila pila;
int error,ok;

AB_Crear(destino,sizeof(TLiteral));
P_Crear(&pila,sizeof(TLiteral));

//inserto la raiz
infijo_a_sufijo("*","",&pila);
P_Sacar(&pila,&literal);

AB_Insertar(destino,RAIZ,&literal,&error);
if (error) return 0;
//>>>>>

//inserto el cos
infijo_a_sufijo("cos","",&pila);
P_Sacar(&pila,&literal);

AB_Insertar(destino,DER,&literal,&error);
if (error) return 0;
//>>>>>>>

Expresion_Copiar_SubExpresion (origen,&expr,DER);
//AB_CopiarSubarbol(origen, &expr, DER);//copia la rama der

ok = Expresion_Derivar (&expr, &deriv);
if (!ok) return 0;

AB_PegarSubarbol( &expr, destino, DER);

AB_MoverCte(destino,RAIZ,&error);
if (error)
  return 0;

AB_PegarSubarbol( &deriv, destino, IZQ);

  AB_Vaciar(&expr);
  AB_Vaciar(&deriv);

return 1;

}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarCoseno(const TAB* origen, TAB* destino) {
  TExpresion u,u1;
  TLiteral literal;
  TPila pila;
  int error;

  P_Crear(&pila,sizeof(TLiteral));
  AB_Crear(destino,sizeof(TLiteral));
  Expresion_Copiar_SubExpresion (origen,&u,DER);  //Genero termino U
  Expresion_Derivar (&u, &u1);          //Genero termino U prima

  infijo_a_sufijo("*","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,RAIZ,&literal,&error);  // RAIZ = *
  AB_PegarSubarbol(&u1,destino,IZQ);  //HIJO IZQ = u1
  AB_MoverCte(destino,RAIZ,&error);

  infijo_a_sufijo("*","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,DER,&literal,&error);  // HIJO DER = *
  infijo_a_sufijo("(-1)","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,IZQ,&literal,&error);  // HIJO DER, HIJO IZQ = -1
  infijo_a_sufijo("sin","",&pila);
  P_Sacar(&pila,&literal);
  AB_MoverCte(destino,PAD,&error);
  AB_Insertar(destino,DER,&literal,&error);  // HIJO DER, HIJO DER = -1
  AB_PegarSubarbol(&u,destino,DER);  // HIJO DER, HIJO DER, HIJO DER = u
  AB_MoverCte(destino,RAIZ,&error);

  AB_Vaciar(&u);
  AB_Vaciar(&u1);

  return 1;
}

/*PRE: Recibe un arbol origen creado y no vacio y otro arbol destino no creado.
  POS: Devuelve la derivada del arbol origen en el arbol destino. Devuelve 1 si deriva, o 0 si ocurre algun error*/
int DerivarLogaritmo(const TAB* origen, TAB* destino) {
  TExpresion u,u1;
  TLiteral literal;
  TPila pila;
  int error;

  P_Crear(&pila,sizeof(TLiteral));
  AB_Crear(destino,sizeof(TLiteral));
  Expresion_Copiar_SubExpresion (origen,&u,DER);  //Genero termino U
  Expresion_Derivar (&u, &u1);          //Genero termino U prima

  infijo_a_sufijo("*","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,RAIZ,&literal,&error); //RAIZ = *
  AB_PegarSubarbol(&u1,destino,IZQ); // HIJO IZQ = U prima
  AB_MoverCte(destino,RAIZ,&error);
  infijo_a_sufijo("/","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,DER,&literal,&error); //HIJO DER = /
  infijo_a_sufijo("1","",&pila);
  P_Sacar(&pila,&literal);
  AB_Insertar(destino,IZQ,&literal,&error); //HIJO DER, HIJO IZQ = 1
  AB_MoverCte(destino,PAD,&error);
  AB_PegarSubarbol(&u,destino,DER); //HIJO DER, HIJO DER = U
  AB_MoverCte(destino,RAIZ,&error);

  AB_Vaciar(&u);
  AB_Vaciar(&u1);

  return 1;
}
